package org.fixies.spreadsheet.interpreter;

import org.fixies.utils.StringUtils;
import org.fixies.utils.UnexpectedProblemException;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static org.fixies.utils.Validator.isNullOrEmpty;
import static org.fixies.utils.Validator.notNullOrEmpty;


/**
 * メタデータノード
 *
 * @author Kawasaki
 */
public class MetadataNode {

    private static final String DEFAULT_METADATA_CHAR = "#";

    /**
     * メタデータを表す正規表現
     */
    private String metaDataRegExp_;

    private String metaDataChar_;

    private int metaDataCharLength_;

    /**
     * メタデータ
     */
    private Map<String, String> metaData_ = new HashMap<String, String>();


    /**
     * デフォルトコンストラクタ
     */
    public MetadataNode() {
        this(DEFAULT_METADATA_CHAR);
    }

    private static String createMetadataRegExp(String metadataChar) {
//		return "^"	+ metadataChar + ".+=.+";
        return "^" + metadataChar + ".*$";
    }

    /**
     * コンストラクタ
     *
     * @param metaDataChar メタデータを表す文字
     */
    public MetadataNode(String metaDataChar) {
        setMetaDataChar(metaDataChar);
    }

    public final void setMetaDataChar(String metadataChar) {
        notNullOrEmpty(metadataChar);
        metaDataChar_ = metadataChar;
        metaDataCharLength_ = getMetaDataCharLength();
        metaDataRegExp_ = createMetadataRegExp(metadataChar);
    }

    /**
     * 評価する。
     *
     * @param context コンテクスト
     */
    public void evaluate(SheetContext context) {
        String[] line = context.current();
        while (isMetaData(line)) {
            storeMetaData(line);
            line = context.next();
        }
    }

    /**
     * 解析結果を取得する。
     *
     * @return 解析結果
     */
    public Map<String, String> getResult() {
        return Collections.unmodifiableMap(metaData_);
    }

    /**
     * メタデータであるか判定する。
     *
     * @param line 行データ
     * @return 判定結果
     */
    boolean isMetaData(String[] line) {
        return !isNullOrEmpty(line) && line[0].matches(metaDataRegExp_);
    }

    /**
     * メタデータを蓄積する。
     *
     * @param line 行データ
     */
    private void storeMetaData(String[] line) {
        String firstCellValue = line[0];
        String[] token = firstCellValue.split("=");

        String metaDataKey;
        String metaDataValue;
        switch (token.length) {
            case 1:
                metaDataValue = "";
                break;
            case 2:
                metaDataValue = token[1];
                break;
            default:
                throw new UnexpectedProblemException("Invalid metadata. line=", StringUtils.join(line), "]");
        }
        metaDataKey = token[0].substring(metaDataCharLength_); // #を取り除く
        metaData_.put(metaDataKey, metaDataValue);
    }

    private int getMetaDataCharLength() {
        return metaDataChar_.replace("\\", "").length();
    }

    /**
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return metaData_.toString();
    }

}
